package net.masker.bbtweet;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

import net.rim.device.api.io.Base64OutputStream;
import net.rim.device.api.system.PersistentObject;
import net.rim.device.api.system.PersistentStore;
import net.rim.device.api.util.Persistable;

public class Properties implements Persistable
{
    private boolean bbtweetEnabled;
    private boolean connectionManagerStarted;
    private long[] lastID = new long[4];
    private int pushStatusUpdate;
    private int statusUpdateRetryAttempts;
    private int friendsInterval;
    private int repliesInterval;
    private int directInterval;
    private String authenticationHash;
    private String bbtweetStatusMessage;
    private String password;
    private String statusUpdate;
    private String username;
	
    // Hash of net.masker.bbtweet.bbtweetProperties.PERSISTENCE_ID 
    private static final long PERSISTENCE_ID = 0xa3388102e219a8a9L;

    // Persistent object wrapping effective properties instance
    private static PersistentObject store;

    // Ensure that an effective properties set exists on startup.
    static {
        store = PersistentStore.getPersistentObject(PERSISTENCE_ID);
        synchronized (store) {
            if (store.getContents() == null) {
                store.setContents(new Properties());
                store.commit();
            }
        }
    }

    /**
     * Retrieves a copy of the effective properties set from storage.
     * 
     * @return the Properties in persistent store.
     */
    public static Properties fetch()
    {
        Properties savedProps =
          (Properties) store.getContents();
        return new Properties(savedProps);
    }        

    /**
     * Class constructor. Sets default values.
     */
    private Properties()
    {
        bbtweetEnabled = false;
        username = "";
        password = "";
        authenticationHash = null;
        friendsInterval = 15;
        repliesInterval = 15;
        directInterval = 15;
        lastID[0] = -1; // friends low id
        lastID[1] = -1;
        lastID[2] = -1; // low between friends & @ id
        lastID[3] = -1; // direct last id
        bbtweetStatusMessage = null;
        connectionManagerStarted = false;
        statusUpdate = "";
        pushStatusUpdate = 0;
        statusUpdateRetryAttempts = 3;
    }

    /**
     * Class constructor. Takes values from another Properties object.
     * 
     * @param Properties object to copy.
     */
    private Properties(Properties other)
    {
    	authenticationHash = other.authenticationHash;
    	bbtweetEnabled = other.bbtweetEnabled;
    	bbtweetStatusMessage = other.bbtweetStatusMessage;
    	connectionManagerStarted = other.connectionManagerStarted;
    	lastID = other.lastID;
    	password = other.password;
    	pushStatusUpdate = other.pushStatusUpdate;
    	statusUpdate = other.statusUpdate;
    	statusUpdateRetryAttempts = other.statusUpdateRetryAttempts;
    	friendsInterval = other.friendsInterval;
    	repliesInterval = other.repliesInterval;
    	directInterval = other.directInterval;
    	username = other.username;       
    }

    /**
     * Retrieves basic authentication hash generated from username and password.
     * 
     * @return String containing authentication hash.
     */
    public String getAuthenticationHash()
    {
    	return authenticationHash;
    }
    
    /**
     * Retrieves current status message.
     * 
     * @return String containing status message.
     */
    public String getBbtweetStatusMessage()
    {
    	return bbtweetStatusMessage;
    }
    
    /**
     * Retrieves last status ID.
     * 
     * @return integer of the last status ID.
     */
    public long getLastID(int index)
    {
    	return lastID[index];
    }
    
    /**
     * Retrieves the state of the push status update process.
     * 
     * @return the integer representing the state of the push status update process.
     * @return 0 IDLE
     * @return 1 PUSHING
     * @return 2 SUCCESS
     * @return 3 FAILURE
     * @return 4 CANCEL
     */
    public int getPushStatusUpdate()
    {
    	return pushStatusUpdate;
    }
    
    /**
     * Retrieves the status update text.
     * 
     * @return the text of the last status update.
     */
    public String getStatusUpdate()
    {
    	return statusUpdate;
    }
    
    /**
     * Retrieves the value of statusUpdateRetryAttempts
     * 
     * @return int statusUpdateRetryAttempts.
     */
    public int getStatusUpdateRetryAttempts()
    {
    	return statusUpdateRetryAttempts;
    }
    
    /**
     * Retrieves the friends update interval in minutes.
     * 
     * @return friends update interval in minutes.
     */
    public int getFriendsInterval()
    {
    	return friendsInterval;
    }
    
    /**
     * Retrieves the replies update interval in minutes.
     * 
     * @return replies update interval in minutes.
     */
    public int getRepliesInterval()
    {
    	return repliesInterval;
    }
    
    /**
     * Retrieves the direct update interval in minutes.
     * 
     * @return direct update interval in minutes.
     */
    public int getDirectInterval()
    {
    	return directInterval;
    }
    
    /**
     * Retrieves the username.
     * 
     * @return String username.
     */
    public String getUsername()
    {
    	return username;
    }
    
    /**
     * Retrieves the state of bbtweet status retrieval.
     * 
     * @return the boolean state of bbtweet status retrieval.
     * @return true Status retrieval is enabled.
     * @return false Status retrieval is disabled.
     */
    public boolean isBbtweetEnabled()
    {
    	return bbtweetEnabled;
    }
    
    /**
     * Retrieves the state of the Connection Manager
     * 
     * @return the boolean state of the Connection Manager.
     * @return true RUNNING.
     * @return false STOPPED.
     */
    public boolean isConnectionManagerStarted()
    {
    	return connectionManagerStarted;
    }

    /**
     * Saves current object values to persistent store.
     */
    public void save()
    {
        // Update authentication hash from current username & password.
    	if ((username.length() > 0) && (password.length() > 0))
    	{
    		byte[] toEncode = (username + ":" + password).getBytes();
    		ByteArrayOutputStream newHash = new ByteArrayOutputStream(toEncode.length);
    		Base64OutputStream base64OutputStream = new Base64OutputStream(newHash);
    		
    		try
    		{
    			base64OutputStream.write(toEncode, 0, toEncode.length);
    			base64OutputStream.flush();
    			base64OutputStream.close();
    		}
    		catch (IOException ioe)
    		{
    			// Null out hash.
    			newHash = null;
    		}
    		
    		// Set authentication hash, clear password.
    		authenticationHash = newHash.toString();
    		password = "";
    	}
    	else if ("".equals(username))
    	{
    		// Set hash to null if username has been cleared.
    		authenticationHash = null;
    	}
    	
    	// Wrap Properties object in perminent store and commit.
    	store.setContents(this);
        store.commit();   
    }
    
    /**
     * Retrieves the state of bbtweet status retrieval.
     * 
     * @param boolean state of status retrieval.
     * @param true Enable status retrieval.
     * @param false Disabled status retrieval.
     */
    public void setBbtweetEnabled(boolean bbtweetEnabledLocal)
    {
    	bbtweetEnabled = bbtweetEnabledLocal;
    }
    
    /**
     * Sets the status message.
     * @param String to set as status message.
     */
    public void setBbtweetStatusMessage(String statusMessageLocal)
    {
    	bbtweetStatusMessage = statusMessageLocal;
    }
    
    /**
     * Sets the state of the Connection Manager.
     * 
     * @param boolean state of the Connection Manager.
     * @param true RUNNING.
     * @param false STOPPED.
     */
    public void setConnectionManagerStarted(boolean connectionManagerStartedLocal)
    {
    	connectionManagerStarted = connectionManagerStartedLocal;
    }
    
    /**
     * Sets the last status ID.
     * 
     * @param integer of last status ID.
     */
    public void setLastID(int index, long newID)
    {
    	lastID[index] = newID;
    }
    
    /**
     * Sets the password.
     * 
     * @param String value of password.
     */
    public void setPassword(String passwordLocal)
    {
    	password = passwordLocal;
    }
    
    /**
     * Sets the state of the push status update process.
     * 
     * @param the integer representing the state of the push status update process.
     * @param 0 IDLE
     * @param 1 PUSHING
     * @param 2 SUCCESS
     * @param 3 FAILURE
     * @param 4 CANCEL
     */
    public void setPushStatusUpdate(int pushStatusUpdateLocal)
    {
    	pushStatusUpdate = pushStatusUpdateLocal;
    }
    
    /**
     * Sets the status update to send.
     * 
     * @param String value of the status update to send.
     */
    public void setStatusUpdate(String statusUpdateLocal)
    {
    	statusUpdate = statusUpdateLocal;
    }
    
    /**
     * Sets the value of statusUpdateRetryAttempts
     * 
     * @param int statusUpdateRetryAttempts.
     */
    public void setStatusUpdateRetryAttempts(int statusUpdateRetryAttemptsLocal)
    {
    	statusUpdateRetryAttempts = statusUpdateRetryAttemptsLocal;
    }
    
    /**
     * Sets the friends update interval in minutes.
     * 
     * @param friends update interval in minutes.
     */
    public void setFriendsInterval(int friendsIntervalLocal)
    {
    	friendsInterval = friendsIntervalLocal;
    }
    
    /**
     * Sets the replies update interval in minutes.
     * 
     * @param replies update interval in minutes.
     */
    public void setRepliesInterval(int repliesIntervalLocal)
    {
    	repliesInterval = repliesIntervalLocal;
    }
    
    /**
     * Sets the direct update interval in minutes.
     * 
     * @param direct update interval in minutes.
     */
    public void setDirectInterval(int directIntervalLocal)
    {
    	directInterval = directIntervalLocal;
    }
    
    /**
     * Sets the username.
     * 
     * @param String username.
     */
    public void setUsername(String usernameLocal)
    {
    	username = usernameLocal;
    }
}